// ImageProcess.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include "ImageProcess.h"

#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>

#define  MAX(x, y)               (x) >= (y) ? (x) : (y)
#define  DBL_EPSILON             2.2204460492503131e-016
#define  CV_MAX_LOCAL_SIZE       1024

inline static int round(double value)
{
	if (value >= 0)
		return (int)(value + 0.5);
	else
		return (int)(value - 0.5);
}

typedef struct CvResizeAlpha
{
	int idx;
	union
	{
		float alpha;
		int ialpha;
	};
}
CvResizeAlpha;

typedef struct CvDecimateAlpha
{
	int si, di;
	float alpha;
}
CvDecimateAlpha;

// typedef struct CvSize
// {
// 	int width;
// 	int height;
// }
// CvSize;

const float g_8x32fTab[] =
{
	-128.f, -127.f, -126.f, -125.f, -124.f, -123.f, -122.f, -121.f,
	-120.f, -119.f, -118.f, -117.f, -116.f, -115.f, -114.f, -113.f,
	-112.f, -111.f, -110.f, -109.f, -108.f, -107.f, -106.f, -105.f,
	-104.f, -103.f, -102.f, -101.f, -100.f,  -99.f,  -98.f,  -97.f,
	-96.f,  -95.f,  -94.f,  -93.f,  -92.f,  -91.f,  -90.f,  -89.f,
	-88.f,  -87.f,  -86.f,  -85.f,  -84.f,  -83.f,  -82.f,  -81.f,
	-80.f,  -79.f,  -78.f,  -77.f,  -76.f,  -75.f,  -74.f,  -73.f,
	-72.f,  -71.f,  -70.f,  -69.f,  -68.f,  -67.f,  -66.f,  -65.f,
	-64.f,  -63.f,  -62.f,  -61.f,  -60.f,  -59.f,  -58.f,  -57.f,
	-56.f,  -55.f,  -54.f,  -53.f,  -52.f,  -51.f,  -50.f,  -49.f,
	-48.f,  -47.f,  -46.f,  -45.f,  -44.f,  -43.f,  -42.f,  -41.f,
	-40.f,  -39.f,  -38.f,  -37.f,  -36.f,  -35.f,  -34.f,  -33.f,
	-32.f,  -31.f,  -30.f,  -29.f,  -28.f,  -27.f,  -26.f,  -25.f,
	-24.f,  -23.f,  -22.f,  -21.f,  -20.f,  -19.f,  -18.f,  -17.f,
	-16.f,  -15.f,  -14.f,  -13.f,  -12.f,  -11.f,  -10.f,   -9.f,
	-8.f,   -7.f,   -6.f,   -5.f,   -4.f,   -3.f,   -2.f,   -1.f,
	0.f,    1.f,    2.f,    3.f,    4.f,    5.f,    6.f,    7.f,
	8.f,    9.f,   10.f,   11.f,   12.f,   13.f,   14.f,   15.f,
	16.f,   17.f,   18.f,   19.f,   20.f,   21.f,   22.f,   23.f,
	24.f,   25.f,   26.f,   27.f,   28.f,   29.f,   30.f,   31.f,
	32.f,   33.f,   34.f,   35.f,   36.f,   37.f,   38.f,   39.f,
	40.f,   41.f,   42.f,   43.f,   44.f,   45.f,   46.f,   47.f,
	48.f,   49.f,   50.f,   51.f,   52.f,   53.f,   54.f,   55.f,
	56.f,   57.f,   58.f,   59.f,   60.f,   61.f,   62.f,   63.f,
	64.f,   65.f,   66.f,   67.f,   68.f,   69.f,   70.f,   71.f,
	72.f,   73.f,   74.f,   75.f,   76.f,   77.f,   78.f,   79.f,
	80.f,   81.f,   82.f,   83.f,   84.f,   85.f,   86.f,   87.f,
	88.f,   89.f,   90.f,   91.f,   92.f,   93.f,   94.f,   95.f,
	96.f,   97.f,   98.f,   99.f,  100.f,  101.f,  102.f,  103.f,
	104.f,  105.f,  106.f,  107.f,  108.f,  109.f,  110.f,  111.f,
	112.f,  113.f,  114.f,  115.f,  116.f,  117.f,  118.f,  119.f,
	120.f,  121.f,  122.f,  123.f,  124.f,  125.f,  126.f,  127.f,
	128.f,  129.f,  130.f,  131.f,  132.f,  133.f,  134.f,  135.f,
	136.f,  137.f,  138.f,  139.f,  140.f,  141.f,  142.f,  143.f,
	144.f,  145.f,  146.f,  147.f,  148.f,  149.f,  150.f,  151.f,
	152.f,  153.f,  154.f,  155.f,  156.f,  157.f,  158.f,  159.f,
	160.f,  161.f,  162.f,  163.f,  164.f,  165.f,  166.f,  167.f,
	168.f,  169.f,  170.f,  171.f,  172.f,  173.f,  174.f,  175.f,
	176.f,  177.f,  178.f,  179.f,  180.f,  181.f,  182.f,  183.f,
	184.f,  185.f,  186.f,  187.f,  188.f,  189.f,  190.f,  191.f,
	192.f,  193.f,  194.f,  195.f,  196.f,  197.f,  198.f,  199.f,
	200.f,  201.f,  202.f,  203.f,  204.f,  205.f,  206.f,  207.f,
	208.f,  209.f,  210.f,  211.f,  212.f,  213.f,  214.f,  215.f,
	216.f,  217.f,  218.f,  219.f,  220.f,  221.f,  222.f,  223.f,
	224.f,  225.f,  226.f,  227.f,  228.f,  229.f,  230.f,  231.f,
	232.f,  233.f,  234.f,  235.f,  236.f,  237.f,  238.f,  239.f,
	240.f,  241.f,  242.f,  243.f,  244.f,  245.f,  246.f,  247.f,
	248.f,  249.f,  250.f,  251.f,  252.f,  253.f,  254.f,  255.f
};

#define CV_8TO32F(x)  g_8x32fTab[(x)+128]

static int ResizeAreaFast(const unsigned char *src, CvSize ssize, unsigned char* dst, CvSize dsize,
						  const int* ofs, const int* xofs)
{                                                                
	int dy, dx, k = 0;                                                          
	int scale_x = ssize.width / dsize.width;                                      
	int scale_y = ssize.height / dsize.height;                                    
	int area = scale_x * scale_y;                                                 
	float scale = 1.f / (scale_x*scale_y);                                                  

	for ( dy = 0; dy < dsize.height; dy++, dst += dsize.width) 
	{
		for ( dx = 0; dx < dsize.width; dx++)               
		{                                                           
			const unsigned char *_src = src + dy*scale_y*ssize.width + xofs[dx]; 
			int sum = 0;                                            

			for (k = 0; k <= area - 4; k += 4)                         
				sum += _src[ofs[k]] + _src[ofs[k+1]] + _src[ofs[k+2]] + _src[ofs[k+3]];                   

			for (; k < area; k++)                                     
				sum += _src[ofs[k]];                                      

			dst[dx] = (unsigned char)round( sum*scale );                
		}                                                                   
	}

	return 1;                                                          
}

static int ResizeArea(const unsigned char* src, int srcstep, CvSize ssize,   
					  unsigned char* dst, int dststep, CvSize dsize,         
					  int cn, const CvDecimateAlpha* xofs,             
					  int xofs_count, float* buf, float* sum)         
{                                                                               
	int k, sy, dx, cur_dy = 0;                                                  
	float scale_y = (float)ssize.height/dsize.height;                           

	srcstep /= sizeof(src[0]);                                                  
	dststep /= sizeof(dst[0]);                                                  
	dsize.width *= cn;                                                          

	for( sy = 0; sy < ssize.height; sy++, src += srcstep )                      
	{                                                                           
		if( cn == 1 )                                                           
			for( k = 0; k < xofs_count; k++ )                                   
			{                                                                   
				int dxn = xofs[k].di;                                           
				float alpha = xofs[k].alpha;                                    
				buf[dxn] = buf[dxn] + CV_8TO32F(src[xofs[k].si])*alpha;        
			}                                                                   
		else if( cn == 2 )                                                      
			for( k = 0; k < xofs_count; k++ )                                   
			{                                                                   
				int sxn = xofs[k].si;                                           
				int dxn = xofs[k].di;                                           
				float alpha = xofs[k].alpha;                                    
				float t0 = buf[dxn] + CV_8TO32F(src[sxn])*alpha;               
				float t1 = buf[dxn+1] + CV_8TO32F(src[sxn+1])*alpha;           
				buf[dxn] = t0; buf[dxn+1] = t1;                                 
			}                                                                   
		else if( cn == 3 )                                                      
			for( k = 0; k < xofs_count; k++ )                                   
			{                                                                   
				int sxn = xofs[k].si;                                           
				int dxn = xofs[k].di;                                           
				float alpha = xofs[k].alpha;                                    
				float t0 = buf[dxn] + CV_8TO32F(src[sxn])*alpha;               
				float t1 = buf[dxn+1] + CV_8TO32F(src[sxn+1])*alpha;           
				float t2 = buf[dxn+2] + CV_8TO32F(src[sxn+2])*alpha;           
				buf[dxn] = t0; buf[dxn+1] = t1; buf[dxn+2] = t2;                
			}                                                                   
		else                                                                    
			for( k = 0; k < xofs_count; k++ )                                   
			{                                                                   
				int sxn = xofs[k].si;                                           
				int dxn = xofs[k].di;                                           
				float alpha = xofs[k].alpha;                                    
				float t0 = buf[dxn] + CV_8TO32F(src[sxn])*alpha;               
				float t1 = buf[dxn+1] + CV_8TO32F(src[sxn+1])*alpha;           
				buf[dxn] = t0; buf[dxn+1] = t1;                                 
				t0 = buf[dxn+2] + CV_8TO32F(src[sxn+2])*alpha;                 
				t1 = buf[dxn+3] + CV_8TO32F(src[sxn+3])*alpha;                 
				buf[dxn+2] = t0; buf[dxn+3] = t1;                               
			}                                                                   

			if( (cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1 )          
			{                                                                       
				float beta = sy + 1 - (cur_dy+1)*scale_y, beta1;                    
				beta = MAX( beta, 0 );                                              
				beta1 = 1 - beta;                                                   
				if( fabs(beta) < 1e-3 )                                             
					for( dx = 0; dx < dsize.width; dx++ )                           
					{                                                               
						dst[dx] = (unsigned char)round(sum[dx] + buf[dx]);           
						sum[dx] = buf[dx] = 0;                                      
					}                                                               
				else                                                                
					for( dx = 0; dx < dsize.width; dx++ )                           
					{                                                               
						dst[dx] = (unsigned char)round(sum[dx] + buf[dx]*beta1);     
						sum[dx] = buf[dx]*beta;                                     
						buf[dx] = 0;                                                
					}                                                               
					dst += dststep;                                                     
					cur_dy++;                                                           
			}                                                                       
			else                                                                    
				for( dx = 0; dx < dsize.width; dx += 2 )                            
				{                                                                   
					float t0 = sum[dx] + buf[dx];                                   
					float t1 = sum[dx+1] + buf[dx+1];                               
					sum[dx] = t0; sum[dx+1] = t1;                                   
					buf[dx] = buf[dx+1] = 0;                                        
				}                                                                   
	}                                                                           

	return 1;                                                               
}


//static int Resize_Area(const unsigned char *src, CvSize ssize, unsigned char* dst, CvSize dsize, 
//					   const CvDecimateAlpha* xofs, int xofs_count, float* buf, float* sum)         
//{                                                                               
//	int k, sy, dx, cur_dy = 0;                                                  
//	float scale_y = (float)ssize.height/dsize.height;                                                     
//
//	for ( sy = 0; sy < ssize.height; sy++, src += ssize.width)                      
//	{                                                                                                                             
//		for (k = 0; k < xofs_count; k++)                                   
//		{                                                                   
//			int dxn = xofs[k].di;                                           
//			float alpha = xofs[k].alpha;                                    
//			buf[dxn] = buf[dxn] + CV_8TO32F(src[xofs[k].si])*alpha;        
//		}                                                                   
//
//		if ((cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1)          
//		{                                                                       
//			float beta = sy + 1 - (cur_dy+1)*scale_y, beta1;                    
//			beta = MAX( beta, 0 );                                              
//			beta1 = 1 - beta;                                                   
//			if( fabs(beta) < 1e-3 ) 
//			{
//				for( dx = 0; dx < dsize.width; dx++ )                           
//				{                                                               
//					dst[dx] = (unsigned char)round(sum[dx] + buf[dx]);           
//					sum[dx] = buf[dx] = 0;                                      
//				}      
//			}
//			else
//			{
//				for( dx = 0; dx < dsize.width; dx++ )                           
//				{                                                               
//					dst[dx] = (unsigned char)round(sum[dx] + buf[dx]*beta1);     
//					sum[dx] = buf[dx]*beta;                                     
//					buf[dx] = 0;                                                
//				}                                                               
//				dst += dsize.width;                                                     
//				cur_dy++;  
//			}
//		}                                                                       
//		else    
//		{
//			for( dx = 0; dx < dsize.width; dx += 2 )                            
//			{                                                                   
//				float t0 = sum[dx] + buf[dx];                                   
//				float t1 = sum[dx+1] + buf[dx+1];                               
//				sum[dx] = t0; sum[dx+1] = t1;                                   
//				buf[dx] = buf[dx+1] = 0;                                        
//			}
//		}
//	}                                                                           
//
//	return 1;                                                               
//}


void resize(const unsigned char *src, CvSize ssize, unsigned char *dst, CvSize dsize)
{
// 	float scale = float(ssize.width)/dsize.width;
// 	for(int i=0; i<dsize.height; ++i)
// 	{
// //		f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1);
// 		 
// 		int x = scale * i;
// 		
// 		float u = scale * i - x;
// 		
// 		for(int j=0; j<dsize.width; ++j)
// 		{
// 			//*(dst + i*dsize.width +j) = src[(int)(scale*i)*ssize.width + (int)(scale*j)];
// 			int y = scale * j;
// 			float v = scale * j - y;
// 			*(dst + i*dsize.width +j) = (1-u)*(1-v)*src[x*ssize.width + y] + (1-u)*v*src[x*ssize.width+y+1] + u*(1-v)*src[(x+1)*ssize.width+y]+u*v*src[(x+1)*ssize.width+y+1];
// 		}
// 	}


	void* temp_buf = 0;
	float scale_x, scale_y;
	int k, sx, sy, dx, cn;

	scale_x = (float)ssize.width/dsize.width;
	scale_y = (float)ssize.height/dsize.height;
	cn = 1;

	if (ssize.width >= dsize.width && ssize.height >= dsize.height )
	{
		//int iscale_x = round(scale_x);
		//int iscale_y = round(scale_y);

		//if( fabs(scale_x - iscale_x) < DBL_EPSILON &&
		//	fabs(scale_y - iscale_y) < DBL_EPSILON )
		//{
		//	int area = iscale_x*iscale_y;
		//	int* ofs = (int*)alloca((area + dsize.width)*sizeof(int));
		//	int* xofs = ofs + area;

		//	for( sy = 0, k = 0; sy < iscale_y; sy++ )
		//		for( sx = 0; sx < iscale_x; sx++ )
		//			ofs[k++] = sy*ssize.width + sx;

		//	for( dx = 0; dx < dsize.width; dx++ )
		//	{
		//		sx = dx*iscale_x;
		//		xofs[dx] = sx;
		//	}

		//	Resize_AreaFast( src, ssize, dst, dsize, ofs, xofs );
		//}
		//else
		//{
		//	int buf_len = dsize.width + 4, buf_size, xofs_count = 0;
		//	float scale = 1.f/(scale_x*scale_y);
		//	float *buf, *sum;
		//	CvDecimateAlpha* xofs;

		//	buf_size = buf_len*2*sizeof(float) + ssize.width*2*sizeof(CvDecimateAlpha);
		//	if( buf_size < CV_MAX_LOCAL_SIZE )
		//		buf = (float*)alloca(buf_size);
		//	else
		//		temp_buf = buf = (float*)malloc(buf_size);
		//	sum = buf + buf_len;
		//	xofs = (CvDecimateAlpha*)(sum + buf_len);

		//	for( dx = 0, k = 0; dx < dsize.width; dx++ )
		//	{
		//		float fsx1 = dx*scale_x, fsx2 = fsx1 + scale_x;
		//		int sx1 = ceil(fsx1), sx2 = floor(fsx2);

		//		assert( (unsigned)sx1 < (unsigned)ssize.width );

		//		if( sx1 > fsx1 )
		//		{
		//			assert( k < ssize.width*2 );            
		//			xofs[k].di = dx;
		//			xofs[k].si = sx1 - 1;
		//			xofs[k++].alpha = (sx1 - fsx1)*scale;
		//		}

		//		for( sx = sx1; sx < sx2; sx++ )
		//		{
		//			assert( k < ssize.width*2 );
		//			xofs[k].di = dx;
		//			xofs[k].si = sx;
		//			xofs[k++].alpha = scale;
		//		}

		//		if( fsx2 - sx2 > 1e-3 )
		//		{
		//			assert( k < ssize.width*2 );
		//			assert((unsigned)sx2 < (unsigned)ssize.width );
		//			xofs[k].di = dx;
		//			xofs[k].si = sx2;
		//			xofs[k++].alpha = (fsx2 - sx2)*scale;
		//		}
		//	}

		//	xofs_count = k;
		//	memset( sum, 0, buf_len*sizeof(float) );
		//	memset( buf, 0, buf_len*sizeof(float) );

		//	ResizeArea(src, ssize.width, ssize, dst, dsize.width, dsize, 1, xofs, xofs_count, buf, sum);
		//}
		int iscale_x = round(scale_x);
		int iscale_y = round(scale_y);

		if( fabs(scale_x - iscale_x) < DBL_EPSILON &&
			fabs(scale_y - iscale_y) < DBL_EPSILON )
		{
			int area = iscale_x*iscale_y;
			int srcstep = ssize.width;
			int* ofs = (int*)alloca( (area + dsize.width*cn)*sizeof(int) );
			int* xofs = ofs + area;

			for( sy = 0, k = 0; sy < iscale_y; sy++ )
				for( sx = 0; sx < iscale_x; sx++ )
					ofs[k++] = sy*srcstep + sx*cn;

			for( dx = 0; dx < dsize.width; dx++ )
			{
				sx = dx*iscale_x*cn;
				for( k = 0; k < cn; k++ )
					xofs[dx*cn + k] = sx + k;
			}

			ResizeAreaFast( src, ssize, dst, dsize, ofs, xofs );
		}
		else
		{
			int buf_len = dsize.width*cn + 4, buf_size, xofs_count = 0;
			float scale = 1.f/(scale_x*scale_y);
			float *buf, *sum;
			CvDecimateAlpha* xofs;

			buf_size = buf_len*2*sizeof(float) + ssize.width*2*sizeof(CvDecimateAlpha);
			if( buf_size < CV_MAX_LOCAL_SIZE )
				buf = (float*)alloca(buf_size);
			else
				temp_buf = buf = (float*)malloc(buf_size);
			sum = buf + buf_len;
			xofs = (CvDecimateAlpha*)(sum + buf_len);

			for( dx = 0, k = 0; dx < dsize.width; dx++ )
			{
				float fsx1 = dx*scale_x, fsx2 = fsx1 + scale_x;
				int sx1 = static_cast<int>(ceil(fsx1)), sx2 = static_cast<int>(floor(fsx2));

				assert( (unsigned)sx1 < (unsigned)ssize.width );

				if( sx1 > fsx1 )
				{
					assert( k < ssize.width*2 );            
					xofs[k].di = dx*cn;
					xofs[k].si = (sx1-1)*cn;
					xofs[k++].alpha = (sx1 - fsx1)*scale;
				}

				for( sx = sx1; sx < sx2; sx++ )
				{
					assert( k < ssize.width*2 );
					xofs[k].di = dx*cn;
					xofs[k].si = sx*cn;
					xofs[k++].alpha = scale;
				}

				if( fsx2 - sx2 > 1e-3 )
				{
					assert( k < ssize.width*2 );
					assert((unsigned)sx2 < (unsigned)ssize.width );
					xofs[k].di = dx*cn;
					xofs[k].si = sx2*cn;
					xofs[k++].alpha = (fsx2 - sx2)*scale;
				}
			}

			xofs_count = k;
			memset( sum, 0, buf_len*sizeof(float) );
			memset( buf, 0, buf_len*sizeof(float) );

			ResizeArea( src, ssize.width, ssize, dst,
				dsize.width, dsize, cn, xofs, xofs_count, buf, sum );
		}
	}
	if (temp_buf)
		free(temp_buf);

}

BOOL ImageToRGB(const ATL::CImage& Image, UCHAR* pR, UCHAR* pG, UCHAR* pB)
{
	int nPitch, nBPP, nPos;
	LPBYTE lpBits;

	if (!pR || !pG || !pB) return FALSE;

	nPitch = Image.GetPitch();
	nBPP = Image.GetBPP();
	lpBits = reinterpret_cast<LPBYTE>(const_cast<VOID *>(Image.GetBits()));

	for (INT i = 0; i < Image.GetHeight(); i++)
	{
		LPBYTE lpBytes = lpBits + (i*nPitch);
		PDWORD lpLines = reinterpret_cast<PDWORD>(lpBytes);

		for (INT j = 0; j < Image.GetWidth(); j++)
		{
			nPos = i*Image.GetWidth() + j;
			pR[nPos] = (UCHAR)((lpLines[j] & 0x00FF0000)>>16);
			pG[nPos] = (UCHAR)((lpLines[j] & 0x0000FF00)>>8);
			pB[nPos] = (UCHAR)(lpLines[j] & 0x000000FF);
		}
	}
/*
	INT front =0;//, back = Image.GetWidth()-1;
	for (INT i = 0; i < 400&&i<Image.GetWidth(); ++i)
	{
		LPBYTE lpBytes = lpBits + i*4;	
		PDWORD lpColor = reinterpret_cast<PDWORD>(lpBytes);
		DWORD dLastColor = lpColor[0];

		INT count = 0;
		for (INT j = 1; j < Image.GetHeight(); ++j)
		{
			LPBYTE lpRowBytes = lpBytes + (j*nPitch);
			PDWORD lpLines = reinterpret_cast<PDWORD>(lpRowBytes);
			if(!(dLastColor ^ lpLines[0]))
			{
				++count;
			}
			//dLastColor = lpLines[0];
		}
		if(count>Image.GetHeight()/2)
			++front;
		else
			break;
	}*/
// 	for (INT i = Image.GetWidth()-1; i > Image.GetWidth()-301 && i>0; --i)
// 	{
// 		LPBYTE lpBytes = lpBits + i*4;	
// 		PDWORD lpColor = reinterpret_cast<PDWORD>(lpBytes);
// 		DWORD dLastColor = lpColor[0];
// 
// 		INT count = 0;
// 		for (INT j = 1; j < Image.GetHeight(); j++)
// 		{
// 			LPBYTE lpRowBytes = lpBytes + (j*nPitch);
// 			PDWORD lpLines = reinterpret_cast<PDWORD>(lpRowBytes);
// 			if(!(dLastColor ^ lpLines[0]))
// 			{
// 				++count;
// 			}
// 			//dLastColor = lpLines[0];
// 		}
// 		if(count>Image.GetHeight()/2)
// 			--back;
// 		else
// 			break;
// 	}
/*
	INT back = Image.GetWidth()-front-1;
	ATL::CImage saveImg;
	saveImg.Create(back-front+1, Image.GetHeight(), 32);
	LPBYTE lpDesBits = reinterpret_cast<LPBYTE>(saveImg.GetBits());

	for(INT i=0; i<Image.GetHeight(); ++i)
	{
		PDWORD pdLineDes = reinterpret_cast<PDWORD>(lpDesBits + i*saveImg.GetPitch());
		PDWORD pdLineSrc = reinterpret_cast<PDWORD>(lpBits + i*Image.GetPitch() +front*4);
		memcpy(pdLineDes, pdLineSrc, 4*saveImg.GetWidth());		
	}

	saveImg.Save(_T("C:\\SnapPic\\m_saveImg.bmp"), Gdiplus::ImageFormatBMP);
*/
	return TRUE;
}

BOOL RGBToImage(const UCHAR* pR, const UCHAR* pG, const UCHAR* pB, ATL::CImage& Image)
{
	int nPitch, nBPP, nPos;
	LPBYTE lpBits;
	DWORD r, g, b;

	if (!pR || !pG || !pB)
		return FALSE;

	nPitch = Image.GetPitch();
	nBPP = Image.GetBPP();
	lpBits = reinterpret_cast<LPBYTE>(Image.GetBits());

	for (INT i = 0; i < Image.GetHeight(); i++)
	{
		LPBYTE lpBytes = lpBits + (i*nPitch);
		PDWORD lpLines = reinterpret_cast<PDWORD>(lpBytes);

		for (INT j = 0; j < Image.GetWidth(); j++)
		{
			nPos = i*Image.GetWidth() + j;
			r = (DWORD)(pR[nPos]);
			r = r<<16;
			g = (DWORD)(pG[nPos]);
			g = g<<8;
			b = (DWORD)(pB[nPos]);
			lpLines[j] = r | g | b;
		}
	}

	return TRUE;
}

BOOL ResizeImage(const ATL::CImage & Image, INT nWidth, INT nHeight//,
	/*UINT * pnSize*//*, BYTE ** ppBitmap, INT * pnComplexScore*/)
{
	BOOL bRet = TRUE;

// 	if (!pnSize )//|| !ppBitmap)
// 		return FALSE;

	////////////////////////////////////////////////////////////////////////////
	// copy src image data
	BITMAP info;
	::GetObject(HBITMAP(Image), sizeof(info), &info);
	UCHAR *pSrcData = new UCHAR[info.bmWidth * info.bmHeight * 3];
	UCHAR *pSrcR = pSrcData;
	UCHAR *pSrcG = pSrcData + info.bmWidth * info.bmHeight;
	UCHAR *pSrcB = pSrcData + 2 * info.bmWidth * info.bmHeight;
	bRet = ImageToRGB(Image, pSrcR, pSrcG, pSrcB);
	if (!bRet)
	{
		return bRet;
	}

	/******************************************************************************/
	// resize RGB
	UCHAR *pDestData = new UCHAR[nWidth * nHeight * 3];
	UCHAR *pDestR = pDestData;
	UCHAR *pDestG = pDestData + nWidth * nHeight;
	UCHAR *pDestB = pDestData + 2 * nWidth * nHeight;


	CvSize SrcSize = {info.bmWidth,  info.bmHeight};
	CvSize DestSize = {nWidth, nHeight};

// 	float scale = float(info.bmWidth)/nWidth;
// 	for(int i=0; i<nHeight; ++i)
// 	{
// 		if(i==306)
// 		{
// 			pDestR[0] = 0;
// 		}
// 		for(int j=0; j<nWidth; ++j)
// 		{
// 			*(pDestR + i*nWidth +j) = (unsigned char)0;//src[(int)(scale*i*ssize.width + scale*j)];
// 			*(pDestG+ i*nWidth +j) = (unsigned char)0;
// 			*(pDestB+ i*nWidth +j) = (unsigned char)0;
// 		}
// 	}



 	resize(pSrcR, SrcSize, pDestR, DestSize);
 	resize(pSrcG, SrcSize, pDestG, DestSize);
 	resize(pSrcB, SrcSize, pDestB, DestSize);

	delete []pSrcData;
	pSrcData = NULL;

 	for(int i=0; i<nHeight; ++i)
 		for(int j=0; j<nWidth; ++j)
 		{
 			if(*(pDestR + i*nWidth +j) > (UCHAR)238)
			{
				*(pDestR + i*nWidth +j) = (UCHAR)250;
			}
			else if(*(pDestR + i*nWidth +j) > (UCHAR)122)
			{
				double dtemp = *(pDestR + i*nWidth +j) * 1.05;
				*(pDestR + i*nWidth +j) = (UCHAR)dtemp;			
			}
 			else
			{
				double dtemp = *(pDestR + i*nWidth +j) /1.2;
  				*(pDestR + i*nWidth +j) = (UCHAR)dtemp;
			}

 			if(*(pDestG + i*nWidth +j) > (UCHAR)238)
			{
 				*(pDestG + i*nWidth +j) = (UCHAR)250;
			}
			else if(*(pDestG + i*nWidth +j) > (UCHAR)122)
			{
				double dtemp = *(pDestG + i*nWidth +j) * 1.05;
				*(pDestG + i*nWidth +j) = (UCHAR)dtemp;		
			}
 			else
			{
				double dtemp = *(pDestG + i*nWidth +j) /1.2;

			}

 			if(*(pDestB + i*nWidth +j) > (UCHAR)238)
			{
				*(pDestB + i*nWidth +j) = (UCHAR)250;
			}
			else if(*(pDestB + i*nWidth +j) > (UCHAR)122)
			{
				double dtemp = *(pDestB + i*nWidth +j) * 1.05;
				*(pDestB + i*nWidth +j) = (UCHAR)dtemp;		
			}
			else
			{
				double dtemp = *(pDestB + i*nWidth +j) /1.2;
			}
 			
 		}

	//////////////////////////////////////////////////////////////////////////
	// copy rgb to image
	ATL::CImage ResizedImage;
	ResizedImage.Create(nWidth, nHeight, 32);

	bRet = RGBToImage(pDestR, pDestG, pDestB, ResizedImage);
	if (!bRet)
	{
		delete [] pDestData;
		pDestData = NULL;
		return bRet;
	}
	
	ResizedImage.Save(L"c:\\SnapPic\\new.bmp", Gdiplus::ImageFormatBMP);

	///////////////////////////////////////////////////////////
	// calculate complex score
// 	if (pnComplexScore)
// 	{
// 		UCHAR * pDestRGB = new UCHAR[nWidth * nHeight * 3];
// 		BITMAP ResizedInfo;
// 		::GetObject(HBITMAP(ResizedImage), sizeof(ResizedInfo), &ResizedInfo);
// 		for (INT i = 0; i < ResizedInfo.bmHeight; i ++)
// 		{
// 			for (INT j = 0; j < ResizedInfo.bmWidth; j ++)
// 			{
// 				INT idx = i * ResizedInfo.bmWidth + j;
// 
// 				COLORREF Color = 0;
// 				Color += (pDestR[idx]) << 16;
// 				Color += (pDestG[idx]) << 8;
// 				Color += (pDestB[idx]);
// 
// 				memcpy((VOID *)(pDestRGB + idx * 3), (VOID *)((UCHAR *)&Color + 1), 3 * sizeof(UCHAR));
// 			}
// 		}
// 		
// 		delete []pDestData;
// 		pDestData = NULL;
// 
// 		UCHAR * pGray = new UCHAR[nHeight * nWidth];
// 		bgr2gray(pDestRGB, nWidth * 3, pGray, nWidth, nWidth, nHeight, 1, 2);
// 		*pnComplexScore = INT(complexity(pGray, nWidth, nHeight) * 100);
// 
// 		delete [] pDestRGB;
// 		pDestRGB = NULL;
// 		delete [] pGray;
// 		pGray = NULL;
// 	}

	//////////////////////////////////////////////////////////////////
	// write to stream
// 	HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, 0);
// 	CComQIPtr<IStream> spImageStream;
// 	HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &spImageStream);
// 	hr = ResizedImage.Save(spImageStream, Gdiplus::ImageFormatJPEG);
// 	if (SUCCEEDED(hr))
// 	{
// 		LARGE_INTEGER ImageBegin = { 0 , 0 };
// 		hr = spImageStream->Seek( ImageBegin , STREAM_SEEK_SET , NULL );
// 
// 		*pnSize = UINT(::GlobalSize(hGlobal));
// 
// 		*ppBitmap = new(std::nothrow) BYTE[(*pnSize) * sizeof(BYTE)];
// 		memset(*ppBitmap, 0, (*pnSize) * sizeof(BYTE));
// 
// 		LPVOID pData = ::GlobalLock(hGlobal);
// 		memcpy(*ppBitmap, pData, *pnSize);
// 		::GlobalUnlock(hGlobal);
// 		::GlobalFree(hGlobal);
// 	}
// 	else
// 	{
// 		bRet = FALSE;
// 	}

	return bRet;
}

#ifdef __cplusplus
extern "C" {
#endif

//#define  MAX(a, b)        ((a) > (b)? (a) : (b))
#define  DESCALE(x,n)     (((x) + (1 << ((n)-1))) >> (n))
#define  fix(x,n)         (int)((x)*(1 << (n)) + 0.5)

#define  csc_shift  14

#define  cscGr_32f  0.299f
#define  cscGg_32f  0.587f
#define  cscGb_32f  0.114f

#define cscGr  fix(cscGr_32f,csc_shift) 
#define cscGg  fix(cscGg_32f,csc_shift)
#define cscGb  ((1 << csc_shift) - cscGr - cscGg)


void derivative(const unsigned char* src, short int *dx, short int *dy, int width, int height)
{
	int i, j, base;

	if (src == NULL || dx == NULL || dy == NULL)
		return;

	memset((void*)dx, 0, width*height*sizeof(short int));
	memset((void*)dy, 0, width*height*sizeof(short int));
	for (i = 1; i < height - 1; i++)
	{
		for (j = 1; j < width - 1; j++)
		{
			base = i*width + j;
			dx[base] = 2*src[base + 1] - 2*src[base - 1] + src[base - width + 1] - 
				src[base - width - 1] + src[base + width + 1] - src[base + width - 1];
			dy[base] = 2*src[base + width] - 2*src[base - width] + src[base + width - 1] - 
				src[base - width - 1] + src[base + width + 1] - src[base - width + 1];
		}
	}
}

void canny(const unsigned char* src, unsigned char* dst, int width, int height, 
		   double low_thresh, double high_thresh)
{
	short int *dx = 0, *dy = 0;
	void *buffer = 0;
	unsigned char **stack_top, **stack_bottom = 0;

	int low, high;
	int* mag_buf[3];
	unsigned char* map;
	int mapstep, maxsize;
	int i, j;
	float *mag_row;

	if( low_thresh > high_thresh )
	{
		double t;
		t = high_thresh;
		high_thresh = low_thresh;
		low_thresh = t;
	}

	dx = new short int[height*width];
	dy = new short int[height*width];

	derivative(src, dx, dy, width, height);

	low = static_cast<int>(floor( low_thresh ));
	high = static_cast<int>(floor( high_thresh ));

	buffer = malloc((width + 2)*(height + 2) + (width + 2)*3*sizeof(int));

	mag_buf[0] = (int*)buffer;
	mag_buf[1] = mag_buf[0] + width + 2;
	mag_buf[2] = mag_buf[1] + width + 2;
	map = (unsigned char*)(mag_buf[2] + width + 2);
	mapstep = width + 2;

	maxsize = MAX( 1 << 10, width*height/10 );
	stack_top = stack_bottom = new unsigned char*[maxsize];

	memset( mag_buf[0], 0, (width+2)*sizeof(int) );
	memset( map, 1, mapstep );
	memset( map + mapstep*(height + 1), 1, mapstep );

#define CANNY_PUSH(d)    *(d) = (unsigned char)2, *stack_top++ = (d)
#define CANNY_POP(d)     (d) = *--stack_top

	mag_row = new float[width];

	for( i = 0; i <= height; i++ )
	{
		int* _mag = mag_buf[(i > 0) + 1] + 1;
		float* _magf = (float*)_mag;
		const short* _dx = dx + width*i;
		const short* _dy = dy + width*i;
		unsigned char* _map;
		int x, y;
		int magstep1, magstep2;
		int prev_flag = 0;

		if( i < height )
		{
			_mag[-1] = _mag[width] = 0;


			for( j = 0; j < width; j++ )
			{
				x = _dx[j]; y = _dy[j];
				_mag[j] = abs(_dx[j]) + abs(_dy[j]);
			}
		}
		else
			memset( _mag-1, 0, (width + 2)*sizeof(int) );

		if( i == 0 )
			continue;

		_map = map + mapstep*i + 1;
		_map[-1] = _map[width] = 1;

		_mag = mag_buf[1] + 1;
		_dx = dx + width*(i-1);
		_dy = dy + width*(i-1);

		magstep1 = (int)(mag_buf[2] - mag_buf[1]);
		magstep2 = (int)(mag_buf[0] - mag_buf[1]);

		if( (stack_top - stack_bottom) + width > maxsize )
		{
			unsigned char** new_stack_bottom;
			maxsize = MAX( maxsize * 3/2, maxsize + width );
			new_stack_bottom = new unsigned char*[maxsize];
			memcpy( new_stack_bottom, stack_bottom, (stack_top - stack_bottom)*sizeof(stack_top[0]) );
			stack_top = new_stack_bottom + (stack_top - stack_bottom);
			delete []stack_bottom;
			stack_bottom = new_stack_bottom;
		}

		for( j = 0; j < width; j++ )
		{
#define CANNY_SHIFT 15
#define TG22  (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5)

			x = _dx[j];
			y = _dy[j];
			int s = x ^ y;
			int m = _mag[j];

			x = abs(x);
			y = abs(y);
			if( m > low )
			{
				int tg22x = x * TG22;
				int tg67x = tg22x + ((x + x) << CANNY_SHIFT);

				y <<= CANNY_SHIFT;

				if( y < tg22x )
				{
					if( m > _mag[j-1] && m >= _mag[j+1] )
					{
						if( m > high && !prev_flag && _map[j-mapstep] != 2 )
						{
							CANNY_PUSH( _map + j );
							prev_flag = 1;
						}
						else
							_map[j] = (unsigned char)0;
						continue;
					}
				}
				else if( y > tg67x )
				{
					if( m > _mag[j+magstep2] && m >= _mag[j+magstep1] )
					{
						if( m > high && !prev_flag && _map[j-mapstep] != 2 )
						{
							CANNY_PUSH( _map + j );
							prev_flag = 1;
						}
						else
							_map[j] = (unsigned char)0;
						continue;
					}
				}
				else
				{
					s = s < 0 ? -1 : 1;
					if( m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s] )
					{
						if( m > high && !prev_flag && _map[j-mapstep] != 2 )
						{
							CANNY_PUSH( _map + j );
							prev_flag = 1;
						}
						else
							_map[j] = (unsigned char)0;
						continue;
					}
				}
			}
			prev_flag = 0;
			_map[j] = (unsigned char)1;
		}

		_mag = mag_buf[0];
		mag_buf[0] = mag_buf[1];
		mag_buf[1] = mag_buf[2];
		mag_buf[2] = _mag;
	}

	while( stack_top > stack_bottom )
	{
		unsigned char* m;
		if( (stack_top - stack_bottom) + 8 > maxsize )
		{
			unsigned char** new_stack_bottom;
			maxsize = MAX( maxsize * 3/2, maxsize + 8 );
			new_stack_bottom = new unsigned char*[maxsize];
			memcpy( new_stack_bottom, stack_bottom, (stack_top - stack_bottom)*sizeof(stack_top[0]) );
			stack_top = new_stack_bottom + (stack_top - stack_bottom);
			delete []stack_bottom;			
			stack_bottom = new_stack_bottom;
		}

		CANNY_POP(m);

		if( !m[-1] )
			CANNY_PUSH( m - 1 );
		if( !m[1] )
			CANNY_PUSH( m + 1 );
		if( !m[-mapstep-1] )
			CANNY_PUSH( m - mapstep - 1 );
		if( !m[-mapstep] )
			CANNY_PUSH( m - mapstep );
		if( !m[-mapstep+1] )
			CANNY_PUSH( m - mapstep + 1 );
		if( !m[mapstep-1] )
			CANNY_PUSH( m + mapstep - 1 );
		if( !m[mapstep] )
			CANNY_PUSH( m + mapstep );
		if( !m[mapstep+1] )
			CANNY_PUSH( m + mapstep + 1 );
	}

	for( i = 0; i < height; i++ )
	{
		const unsigned char* _map = map + mapstep*(i+1) + 1;
		unsigned char* _dst = dst + width*i;

		for( j = 0; j < width; j++ )
			_dst[j] = (unsigned char)-(_map[j] >> 1);
	}

	delete []dx;
	delete []dy;
	free(buffer);
	delete []stack_bottom;
}

void bgr2gray(const unsigned char* src, int srcstep,
			  unsigned char* dst, int dststep, int width, int height,
			  int src_cn, int blue_idx)
{
	int i;
	srcstep -= width*src_cn;

	if ( width*height >= 1024 )
	{
		int* tab = (int*)alloca( 256*3*sizeof(tab[0]) );
		int r = 0, g = 0, b = (1 << (csc_shift-1));

		for ( i = 0; i < 256; i++ )
		{
			tab[i] = b;
			tab[i+256] = g;
			tab[i+512] = r;
			g += cscGg;
			if ( !blue_idx )
				b += cscGb, r += cscGr;
			else
				b += cscGr, r += cscGb;
		}

		for ( ; height--; src += srcstep, dst += dststep )
		{
			for( i = 0; i < width; i++, src += src_cn )
			{
				int t0 = tab[src[0]] + tab[src[1] + 256] + tab[src[2] + 512];
				dst[i] = (unsigned char)(t0 >> csc_shift);
			}
		}
	}
	else
	{
		for( ; height--; src += srcstep, dst += dststep )
		{
			for( i = 0; i < width; i++, src += src_cn )
			{
				int t0 = src[blue_idx]*cscGb + src[1]*cscGg + src[blue_idx^2]*cscGr;
				dst[i] = (unsigned char)DESCALE(t0, csc_shift);
			}
		}
	}
}

double complexity(const unsigned char* src, int width, int height)
{
	double p[256];
	int level;
	double scale = 1.0/(width*height);
	double entropy = 0.0; 

	memset(p, 0, sizeof(p));

	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			level = src[i*width + j];
			p[level] += 1;
		}
	}

	for (int i = 0; i < 256; i++)
		p[i] *= scale;

	for (int i = 0; i < 256; i++)
	{
		if (p[i])
			entropy += -p[i]*log(p[i]);
	}

	return entropy;
}

#ifdef __cplusplus
}
#endif